
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Matrix Calculator takes two matrices in XML format and
 * multiplies the first matrix with the second matrix.
 *
 * This class is used for running the program.
 *
 * @author Corvus, Janne
 */
public class Main {

    private static DateFormat df = new SimpleDateFormat("HH:mm:ss.SSS");

    public static void printMemoryUse() {
        long heapSize = Runtime.getRuntime().totalMemory();
        long heapMaxSize = Runtime.getRuntime().maxMemory();
        long freeMemory = Runtime.getRuntime().freeMemory();
        print("Memory allocated: " + heapSize + " Memory used: " + (heapSize - freeMemory) + " Max memory: " + heapMaxSize);
    }

    public static void print(String s) {
        System.out.println("[" + df.format(new Date()) + "] " + s);
    }

    private static void gc() {
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
        }
    }

    public static void main(String[] args) {
        printMemoryUse();
        MatrixCalculatorController controller = new MatrixCalculatorController(true);

        print("Starting.");

        if (args.length < 2) {
            print("Missing arguments.");
        }

        if (args[0].equals("-r")) {            
            int n = Integer.parseInt(args[1]);
            print("Creating random matrices of size " + n + " x " + n + ".");
            controller.initialize(n, n, n, n);
        } else {
            print("Loading matrices");
            controller.initialize(args[0], args[1]);
        }

        print("Matrices read.");

        if (new File("serial_result.bin").exists()) {
            print("Reading serial results from file.");
            controller.loadSerialResult("serial_result.bin");
        } else {
            print("Start serial run.");
            controller.doSerial();
            print("Serial run complete.");
        }

        gc();

        for (int i = 1; i <= Runtime.getRuntime().availableProcessors(); i++) {
            print("Start concurrent run with " + i + " threads.");
            controller.doConcurrent(i);
            print("Done.");

            gc();

            for (int j = 0; j < 3; j++) {

                print("Start concurrent run with " + i + " threads.");
                controller.doConcurrent(i);
                print("Done.");
                
                print("Write results to log.");
                controller.doFinish();
                print("Done.");

                gc();
            }
        }

        controller.doEnd();
        print("All done, exit");
    }
}
